﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.ComponentModel;
using System.Runtime.Serialization;
using System.Collections.Generic;
using System.Collections;
using System.ComponentModel.DataAnnotations;
using System.Linq;
namespace Biciq.Silverlight.UI
{
   
        [DataContract]
        public class ViewModelBase : INotifyPropertyChanged, INotifyDataErrorInfo
        {
            #region fields
            private bool _isDirty;
            #endregion
            #region eventos
            public event PropertyChangedEventHandler PropertyChanged;
            #endregion
            #region Comandos
            public RelayCommand RelayCommand;
            #endregion

            #region propiedades
            [DataMember]
            /// <summary>
            /// Debe true cuando hay cambios en alguna propiedad del view model
            /// y false en caso contrario
            /// </summary>
            public bool IsDirty
            {
                get { return _isDirty; }
                set
                {
                    _isDirty = value;
                    RaisePropertyChanged("IsDirty");
                }
            }

            #endregion

            #region metodos publicos
            /// <summary>
            /// Notifica a la interface que hubo cambios en las propiedades del view model
            /// </summary>
            /// <param name="propertyName">Nombre de la propiedad a notificar a la vista</param>
            public void RaisePropertyChanged(string propertyName)
            {
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

                }

            }

            #endregion

            #region INotifyDataErrorInfo Members

            /// <summary> 
            /// Permet d'indiquer qu'une erreur de validation est présente 
            /// </summary> 
            public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;
            protected void NotifyErrorsChanged(string propertyName)
            {
                if (ErrorsChanged != null)
                    ErrorsChanged(this, new DataErrorsChangedEventArgs(propertyName));
            }


            private readonly IDictionary<string, IList<string>> _errors = new Dictionary<string, IList<string>>();
            public IEnumerable GetErrors(string propertyName)
            {
                if (_errors.ContainsKey(propertyName))
                {
                    IList<string> propertyErrors = _errors[propertyName];
                    foreach (string propertyError in propertyErrors)
                    {
                        yield return propertyError;
                    }
                }
                yield break;
            }

            public bool HasErrors { get { return _errors.Count > 0; } }


            protected void ValidateProperty(string propertyName, object value)
            {
                ViewModelBase objectToValidate = this;
                ValidationContext vctx = new ValidationContext(objectToValidate, null, null)
                                                {
                                                    MemberName = propertyName
                                                };
                var results = new List<ValidationResult>();
                bool isValid = Validator.TryValidateProperty(value, vctx, results);

                if (isValid)
                    RemoveErrorsForProperty(propertyName);
                else
                    AddErrorsForProperty(propertyName, results);
                NotifyErrorsChanged(propertyName);
            }

            private void AddErrorsForProperty(string propertyName, IEnumerable<ValidationResult> validationResults)
            {
                RemoveErrorsForProperty(propertyName);
                _errors.Add(propertyName, validationResults.Select(vr => vr.ErrorMessage).ToList());
            }

            private void RemoveErrorsForProperty(string propertyName)
            {
                if (_errors.ContainsKey(propertyName))
                    _errors.Remove(propertyName);
            }

            public bool ValidateObject()
            {
                ViewModelBase objectToValidate = this;
                _errors.Clear();
                var results = new List<ValidationResult>();
                bool isValid = Validator.TryValidateObject(objectToValidate, new ValidationContext(objectToValidate, null, null), results, true);
                if (!isValid)
                {
                    IEnumerable<string> propertiesWithMessage = results.SelectMany(vr => vr.MemberNames);
                    foreach (string property in propertiesWithMessage)
                    {
                        IEnumerable<ValidationResult> messages = results.Where(vr => vr.MemberNames.Contains(property));
                        AddErrorsForProperty(property, messages);
                        NotifyErrorsChanged(property);
                    }
                }
                return isValid;
            }

            #endregion
        }
            
    
}
